/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package game;

import java.io.IOException;
import java.util.Random;

import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.Sprite;

/**
 * Alien KI
 * @author simon
 */
public class Alien {
        public static final int T_SLOW_ALIEN = 0;
        public static final int T_FAST_ALIEN = 1;

        public static final int D_NONE = -1;
		public static final int D_UP = 0;
		public static final int D_RIGHT = 1;
		public static final int D_DOWN = 2;
		public static final int D_LEFT = 3;

		public static final int A1_ANIM_DELAY = 4;
        public static final int A2_ANIM_DELAY = 3;

        public static final int A1_ANIM_FRAME[][] = {
        	{ 4,  5,  6,  7},
        	{12, 13, 14, 15},
        	{ 0,  1,  2,  3},
        	{ 8,  9, 10, 11},
        };

        public static final int A1_ANIM_FRAME_DEATH[] = {
        	16, 17, 18, 19, 20, 21, 22, 23
        };

        public static final int A2_ANIM_FRAME[][] = {
        	{4, 5},
        	{6, 7},
        	{0, 1, 2, 3},
        	{8, 9},
        };

        public static final int A2_ANIM_FRAME_DEATH[] = {
        	10, 11, 12, 13, 14, 15, 16, 17
        };

        final int ANIM_FRAME[][];
        final int ANIM_FRAME_DEATH[];
        final int ANIM_DELAY;

        static Image image_slow = null;
        static Image image_fast = null;
        Sprite gfx = null;

        float x, y;
        int tile_x, tile_y;
        int next_x, next_y;
        float speed;
        int animFrame;
        int animDelay;
        int direction;
        int movesLeft;
        int dead;
        int type;
        Random random;

        private void updateSprite() {
        	if (direction == D_NONE) {
        		gfx.setFrame(ANIM_FRAME[D_DOWN][0]);
        	} else {
        		gfx.setFrame(ANIM_FRAME[direction][animFrame]);
        	}
			gfx.setPosition((int)x + 10, (int)y + 10);
		}

        /**
         * Create alien of given type at tile position (tile_x, tile_y)
         * @param type type of alien (fast or slow)
         * @param tile_x position x
         * @param tile_y position y
         */
        public Alien( int type, int tile_x, int tile_y )
        {
            if (type == T_SLOW_ALIEN) {
                ANIM_FRAME = A1_ANIM_FRAME;
                ANIM_FRAME_DEATH = A1_ANIM_FRAME_DEATH;
                ANIM_DELAY = A1_ANIM_DELAY;
                try {
                	if (image_slow == null) {
                		image_slow = Image.createImage("/gfx/alien_tile.png");
                	}
                    gfx = new Sprite(image_slow, 20, 20);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                speed = 1.0f;
            } else if (type == T_FAST_ALIEN) {
                ANIM_FRAME = A2_ANIM_FRAME;
                ANIM_FRAME_DEATH = A2_ANIM_FRAME_DEATH;
                ANIM_DELAY = A2_ANIM_DELAY;
                try {
                	if (image_fast == null) {
                		image_fast = Image.createImage("/gfx/fast_alien-tile.png");
                	}
                    gfx = new Sprite(image_fast, 20, 20);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                speed = 2.0f;
            } else {
                throw new Error("Wrong type");
            }
            dead = 0;
            animFrame = 0;
            animDelay = ANIM_DELAY;
            this.tile_x = tile_x;
            this.tile_y = tile_y;
            x = tile_x * Arena.TILESIZE;
            y = tile_y * Arena.TILESIZE;
            direction = D_NONE;
            movesLeft = 0;
            this.type = type;
            
            updateSprite();
            
            this.random = new Random();
        }
        
        private int[] nextPosition(int direction) {
    		int next_x = tile_x;
    		int next_y = tile_y;
    		switch (direction) {
    		case D_UP: next_y--; break;
    		case D_RIGHT: next_x++; break;
    		case D_DOWN: next_y++; break;
    		case D_LEFT: next_x--; break;
    		}
    		int[] ret = {next_x, next_y};
    		return ret;
        }
        
        /**
         * calculate next move
         * @param arena the game arena
         */
        public void nextMove(Arena arena) {
        	final int[] nextDirection_none = {D_UP, D_LEFT, D_DOWN, D_RIGHT};
        	final int[] nextDirection_left = {D_LEFT, D_UP, D_DOWN, D_RIGHT};
        	final int[] nextDirection_right = {D_RIGHT, D_DOWN, D_UP, D_LEFT};
        	final int[] nextDirection_up = {D_UP, D_LEFT, D_RIGHT, D_DOWN};
        	final int[] nextDirection_down = {D_DOWN, D_RIGHT, D_LEFT, D_UP};

        	final int[] probabilities_none = {25, 25, 25, 25};
        	final int[] probabilities_normal = {50, 20, 20, 10};
        	
        	int[] nextDirection;
        	int[] probabilities;
        	
        	switch (direction) {
        	case D_NONE: nextDirection = nextDirection_none; probabilities = probabilities_none; break;
        	case D_LEFT: nextDirection = nextDirection_left; probabilities = probabilities_normal; break;
        	case D_RIGHT: nextDirection = nextDirection_right; probabilities = probabilities_normal; break;
        	case D_UP: nextDirection = nextDirection_up; probabilities = probabilities_normal; break;
        	case D_DOWN: nextDirection = nextDirection_down; probabilities = probabilities_normal; break;
        	default: throw new Error("Invalid direction");
        	}
        	
        	int totalProbability = 0;
        	for (int i=0; i<4; ++i) {
        		int[] nextPos = nextPosition(nextDirection[i]);
        		int next_x = nextPos[0];
        		int next_y = nextPos[1];
        		if(arena.isTileBlocked(next_x, next_y) || arena.hasAlien(next_x, next_y)) {
        			probabilities[i] = 0;
        		} else {
        			totalProbability += probabilities[i];
        		}
        	}
        	
        	if (totalProbability <= 0) {
        		direction = D_NONE;
        		animFrame = 0;
        		animDelay = ANIM_DELAY;
        		movesLeft = 0;
        		return;
        	}
        	
        	int rndIndex = Math.abs(random.nextInt()) % totalProbability;
        	int sum = 0;
        	for (int i=0; i<4; ++i) {
        		sum += probabilities[i];
        		if (rndIndex < sum) {
        			direction = nextDirection[i];
        			animFrame = 0;
        			animDelay = ANIM_DELAY;
        			movesLeft = (int) (Arena.TILESIZE / this.speed);
        			int[] nextPos = nextPosition(direction);
        			this.next_x = nextPos[0];
        			this.next_y = nextPos[1];
        			return;
        		}
        	}
        	
        	throw new Error("Weird random stuff");
        }
        
        /**
         * kill the alien
         */
    	public void kill() {
    		if (dead == 0) {
	    		dead = 1;
	    		animFrame = 0;
	    		animDelay = ANIM_DELAY;
    		}
    	}
    	
    	/**
    	 * draw the alien
    	 * @param g graphics environment
    	 */
    	public void draw(Graphics g) {
    		if (dead < 2) gfx.paint(g);
    	}
    	
    	/**
    	 * execute alien logic
    	 * @param arena
    	 */
    	public void logic(Arena arena) {
    		if (dead == 2) {
    			return;
    		}
    		if (dead == 1) {
    			animDelay--;
    			if (animDelay <= 0) {
    				animDelay = ANIM_DELAY;
    				animFrame++;
    				if (animFrame < ANIM_FRAME_DEATH.length) {
    					gfx.setFrame(ANIM_FRAME_DEATH[animFrame]);
    				} else {
    					dead = 2;
    				}
    			}
    			return;
    		}
    		if (movesLeft <= 0) {
    			nextMove(arena);
    		}
    		
    		if (movesLeft > 0 && direction != D_NONE) {
    			animDelay--;
    			if (animDelay <= 0) {
    				animDelay = ANIM_DELAY;
    				animFrame++;
    				animFrame %= ANIM_FRAME[direction].length;
    			}
    			switch (direction) {
    			case D_LEFT: x -= speed; break;
    			case D_RIGHT: x += speed; break;
    			case D_UP: y -= speed; break;
    			case D_DOWN: y += speed; break;
    			}
    			movesLeft--;
    			if (movesLeft <= 0) {
    				tile_x = next_x;
    				tile_y = next_y;
    				x = tile_x * Arena.TILESIZE;
    				y = tile_y * Arena.TILESIZE;
    			}
    		}
    		
    		updateSprite();
    	}
    	
    	/**
    	 * 
    	 * @return true if alien is dead or dieing
    	 */
    	public boolean isDead() {
    		return (dead > 1);
    	}
    	
    	/**
    	 * x in tile coordinates
    	 * @return
    	 */
    	public int getTileX() {
    		return (((int)this.x) + Arena.TILESIZE/2) / Arena.TILESIZE;
    	}
    	
    	/**
    	 * y in tile coordinates
    	 * @return
    	 */
    	public int getTileY() {
    		return (((int)this.y) + Arena.TILESIZE/2) / Arena.TILESIZE;
    	}
}
